package com.ydlclass.channelHandler.handler;

import com.ydlclass.compress.Factory.CompressFactory;
import com.ydlclass.enumeration.RequestType;
import com.ydlclass.serialize.Factory.SerializeFactory;
import com.ydlclass.transport.message.MessageFormatConstant;
import com.ydlclass.transport.message.RequestPayload;
import com.ydlclass.transport.message.YrpcRequest;
import com.ydlclass.transport.message.YrpcResponse;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

/**
 * 基于长度字段的解码器
 * 加码器
 * @author Knife
 */
@Slf4j
public class YrpcResponseDecoder extends LengthFieldBasedFrameDecoder {

    public YrpcResponseDecoder() {
        super(
                // 找到当前报文的总长度，截取报文，截取出来的报文进行解析
        // 最大帧长度，超过这个maxFrameLength的值会直接丢弃
        MessageFormatConstant.MAX_FRAME_LENGTH,
        // 长度字段的偏移量
        MessageFormatConstant.MAGIC.length + MessageFormatConstant.VERSION_LENGTH + MessageFormatConstant.HEADER_FIELD_LENGTH,
        // 长度的字段的长度
        MessageFormatConstant.FULL_FIELD_LENGTH,
        // todo 负载的适配长度
        -(MessageFormatConstant.MAGIC.length + MessageFormatConstant.VERSION_LENGTH + MessageFormatConstant.HEADER_FIELD_LENGTH + MessageFormatConstant.FULL_FIELD_LENGTH),
        0);
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        Object decode = super.decode(ctx, in);
        if (decode instanceof ByteBuf byteBuf){
            return decodeFrame(byteBuf);
        }
            return null;
    }

    private Object decodeFrame(ByteBuf byteBuf) {
        // 解析ByteBuf
        // 1、解析魔术值
        byte [] magic = new byte[MessageFormatConstant.MAGIC.length];
        byteBuf.readBytes(magic);
        // 检测魔数是否匹配
        for (int i = 0; i < magic.length; i++) {
            if (magic[i] != MessageFormatConstant.MAGIC[i]){
                throw new RuntimeException("The obtained request is not valid");
            }
        }
        // 2、解析版本号
        byte version = byteBuf.readByte();
        if (version > MessageFormatConstant.VERSION){
            throw new RuntimeException("The obtained version is not supported");
        }
        // 3、解析头部的长度是否合法
        short headerLength = byteBuf.readShort();
        if (headerLength != MessageFormatConstant.HEADER_LENGTH){
            throw new RuntimeException("");
        }
        // 4、解析总长度
        int fullLength = byteBuf.readInt();
        // 5、请求类型
        byte responseCode = byteBuf.readByte();
        // 6、序列化类型
        byte serializeType = byteBuf.readByte();
        // 7、压缩类型
        byte compressType = byteBuf.readByte();
        // 8、请求id
        long requestId = byteBuf.readLong();
        // 9、响应时间
        long timeStamp = byteBuf.readLong();

        // todo 在这之前我们需要进行封装我们需要返回的对象

        YrpcResponse response = YrpcResponse.builder()
                .requestId(requestId)
                .responseCode(responseCode)
                .compressType(compressType)
                .serializeType(serializeType)
                .timeStamp(timeStamp)
                .build();

        // todo 心跳请求没有负载，此处可以判断并直接返回
//        if (requestType == RequestType.HEART_BEAT.getId()){
//            return request;
//        }

        // 读取负载body -->消息内容
        int bodyLength = fullLength - headerLength;
        byte [] payload = new byte[bodyLength];
        byteBuf.readBytes(payload);

        //有了字节数组之后我们就可以进行解压缩，反序列化
        //  解压缩
        Object body = null;
        if (payload != null && payload.length > 0){
            payload = CompressFactory
                    .getCompressor(compressType)
                    .getCompressor()
                    .decompress(payload);

            //  反序列化
            body = SerializeFactory
                    .getSerializer(serializeType)
                    .getSerializer()
                    .deserialize(payload, Object.class);
        }


        response.setBody(body);

        if(log.isDebugEnabled()){
            log.debug("ResponseDecoder响应{}已经在服务端完成解码工作：{}",requestId);
        }

        return response;
    }

}
